package cn.sylinx.hbatis.ext.model;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import cn.sylinx.hbatis.db.mapper.ModelBuilder;
import cn.sylinx.hbatis.exception.HbatisException;

@SuppressWarnings({ "unchecked", "serial" })
public class Model implements Serializable, Cloneable {

	private static final String NULLABLE_FIELDS = "NULLABLE_FIELDS";
	/**
	 * 自定义属性
	 */
	private Map<String, Object> context = new HashMap<String, Object>();

	public Map<String, Object> getContext() {
		return context;
	}

	/**
	 * 对应属性可设置为空
	 * 
	 * @param attributeName
	 * @return
	 */
	public <T extends Model> T withNullable(String attributeName) {
		getNullableFields().add(attributeName);
		return (T) this;
	}

	/**
	 * 对应属性可设置为空
	 * 
	 * @param attributeNames
	 * @return
	 */
	public <T extends Model> T withNullables(String... attributeNames) {
		if (attributeNames != null) {
			for (String attributeName : attributeNames) {
				getNullableFields().add(attributeName);
			}
		}
		return (T) this;
	}

	/**
	 * 清空可空字段
	 * 
	 * @return
	 */
	public <T extends Model> T removeNullable() {
		getNullableFields().clear();
		return (T) this;
	}

	/**
	 * 将所有字段可设置为空
	 * 
	 * @return
	 */
	public <T extends Model> T withNullable() {
		List<Field> fieldList = ModelBuilder.getObjectAllFields(this.getClass());
		for (Field f : fieldList) {
			withNullable(f.getName());
		}
		return (T) this;
	}

	/**
	 * 获取所有可设置空字段
	 * 
	 * @return
	 */
	public Set<String> getNullableFields() {
		Object object = context.get(NULLABLE_FIELDS);
		if (object == null) {
			object = new HashSet<String>();
			context.put(NULLABLE_FIELDS, object);
		}

		return (Set<String>) object;
	}

	@Override
	public Object clone() {

		Model cloneObject = null;
		try {
			cloneObject = (Model) super.clone();
		} catch (CloneNotSupportedException e) {
			throw new HbatisException(e);
		}

		if (cloneObject != null) {
			cloneObject.context = new HashMap<String, Object>();
			// 深度克隆 context
			Iterator<Entry<String, Object>> iterator = context.entrySet().iterator();
			while (iterator.hasNext()) {
				Entry<String, Object> entry = iterator.next();
				cloneObject.context.put(entry.getKey(), entry.getValue());
			}
		}

		return cloneObject;
	}

}
